#include <linux/fs.h>
#include "drv_cdev.h"

/* 初始化字符设备的类和申请足够的设备号 */
int init_cdev_ctrl(void *parent, struct cdev_ctrl_t *pctrl,
                   const char *name, u8 max_num)
{
    int ret = 0;

    /* 检查参数是否有效 */
    if (!parent || !pctrl || !name) {
        pr_err("Invalid parameters for %s, %p, %p, %p", 
               __func__, parent, pctrl, name);
        return -EINVAL;
    }

    pctrl->parent = parent;
    strscpy(pctrl->name, name, sizeof(pctrl->name));
    pctrl->cclass = class_create(THIS_MODULE, pctrl->name);
    if (IS_ERR(pctrl->cclass)) {
        ret = PTR_ERR(pctrl->cclass);
        pr_err("Create %s class failed", pctrl->name);
        return ret;
    }
    pr_debug("Create %s class success", pctrl->name);
    pctrl->max_num = max_num;
    ret = alloc_chrdev_region(&pctrl->major_devno, 0, pctrl->max_num, pctrl->name);
    if (ret) {
        pr_err("Allocate device number for %s failed, (err=%d)",
                pctrl->name, ret);
    }
    pr_debug("Allocate %d %s major devno %d success", pctrl->max_num, pctrl->name, MAJOR(pctrl->major_devno));

    return ret;
}

/* 注销字符设备的类和所有申请的设备号*/
void exit_cdev_ctrl(struct cdev_ctrl_t *pctrl)
{
    /* 检查参数是否有效 */
    if (!pctrl) {
        pr_err("Invalid parameters for %s", __func__);
    }
    unregister_chrdev_region(pctrl->major_devno, pctrl->max_num);
    pr_debug("Unregistered cdev region for all %s",
            pctrl->name);

    class_destroy(pctrl->cclass);
    pr_info("Destroy %s class success", pctrl->name);
}

/* 初始化字符设备 */
int init_cdev_dev(void *parent, struct class *cdev_class, struct cdev_dev_t *cdev_dev, 
                  const struct file_operations *fops, dev_t major_devno,
                  const char *name, u8 index)
{
    int ret = 0;

    /* 检查参数是否有效 */
    if (!parent || !cdev_class || !cdev_dev || !fops || !name) {
        pr_err("Invalid parameters for %s, %p, %p, %p, %p, %p", 
               __func__, parent, cdev_class, cdev_dev, fops, name);
        return -EINVAL;
    }

    cdev_dev->parent = parent;
    strscpy(cdev_dev->name, name, sizeof(cdev_dev->name));
    cdev_dev->index = index;
    cdev_dev->fops = fops;
    cdev_init(&cdev_dev->cdev, fops);
    cdev_dev->cdev.owner = THIS_MODULE;

    cdev_dev->devno = MKDEV(MAJOR(major_devno), index);
    ret = cdev_add(&cdev_dev->cdev, cdev_dev->devno, 1);
    if (ret) {
        pr_err("Add cdev for %s failed, (err=%d)",
                cdev_dev->name, ret);
        goto err_unregister_dev;
    }
    pr_debug("Add cdev%d for %s major=%u minor=%u success", 
             cdev_dev->index, 
             cdev_dev->name, 
             MAJOR(cdev_dev->devno), 
             MINOR(cdev_dev->devno));

    /* 创建 sysfs 中的设备节点 */
    cdev_dev->dev = device_create(cdev_class, NULL, cdev_dev->devno, NULL,
                                 "%s", cdev_dev->name);
    if (IS_ERR(cdev_dev->dev)) {
        pr_err("Create device node for %s failed",
                cdev_dev->name);
        ret = PTR_ERR(cdev_dev->dev);
        goto err_remove_cdev;
    }
    pr_debug("Create device node /dev/%s success",
            cdev_dev->name);

    return 0;

err_remove_cdev:
    cdev_del(&cdev_dev->cdev);
    pr_debug("Remove cdev for %s during error handling",
            cdev_dev->name);

err_unregister_dev:
    unregister_chrdev_region(cdev_dev->devno, 1);
    pr_debug("Unregistered cdev region for %s",
            cdev_dev->name);

    return ret;
}

/* 注销字符设备 */
void exit_cdev_dev(struct class *cdev_class, struct cdev_dev_t *cdev_dev)
{
    /* 检查参数是否有效 */
    if (!cdev_class || !cdev_dev) {
        pr_err("Invalid parameters for %s, %p %p", 
               __func__, cdev_class, cdev_dev);
        return;
    }

    device_destroy(cdev_class, cdev_dev->devno);
    pr_debug("Destroyed device node for %s",
             cdev_dev->name);

    cdev_del(&cdev_dev->cdev);
    pr_debug("Removed cdev for %s", cdev_dev->name);

    unregister_chrdev_region(cdev_dev->devno, 1);
    pr_debug("Unregistered cdev region for %s",
             cdev_dev->name);
}
